'use strict';

const { Service } = require('ee-core');
const { SerialPort } = require('serialport');
const ModbusRTU = require("modbus-serial");
const crc16 = require('crc').crc16;
// const Electron = require('ee-core/electron');
const { sendMsg } = require('../common');
/**
 * 示例服务（service层为单例）
 * @class
 */
class ModbusRTUService extends Service {

  constructor(ctx) {
    super(ctx);
    this.client = new ModbusRTU();
    this.client.setTimeout(1000);


    // Upon SerialPort error
    this.client.on("error", function(error) {
        console.log("SerialPort Error: ", error);
    });

    this.client.on('close', function() {
      console.log('Connection closed');
      sendMsg('close', 'rtuclose')
    })

    this.client._debugEnabled = true;

  }

  // 构建请求帧的函数
  async buildModbusRequest(functionCode, startAddress, quantity) {
    
      // 创建请求帧的字节数组
      let request = new Uint8Array(7); // Modbus RTU帧通常是7个字节（地址+功能码+数据+CRC16）
      request[0] = 0x01; // 设备地址（例如，0x01）
      request[1] = functionCode; // 功能码（例如，0x03表示读取保持寄存器）
      request[2] = (startAddress >> 8) & 0xFF; // 起始地址的高字节
      request[3] = startAddress & 0xFF; // 起始地址的低字节
      request[4] = (quantity >> 8) & 0xFF; // 要读取的数量（可选，取决于功能码）
      request[5] = quantity & 0xFF; // 要读取的数量（可选，取决于功能码）
      // 计算CRC16并添加到帧的末尾
      const crc = crc16(request); // 注意：在某些实现中，你可能需要传入不带CRC的数据部分进行计算
      request[5] = crc & 0xFF; // CRC的低字节
      request[6] = (crc >> 8) & 0xFF; // CRC的高字节
      return request;
  }

  // 获取串口列表
  async serialList() { 
    const list = []
    await SerialPort.list().then(ports => {
      // 可用串口列表
      ports.forEach(port => {
        // console.log(`端口: ${port.path}`, `制造商: ${port.manufacturer || '未知'}`);
        list.push({ 'path': port.path, 'manufacturer': port.manufacturer || '未知' })
      });
    }).catch(err => {
      console.error('获取串口列表时出错:', err);
      return list;
    });

    return list;
  }

  // 连接串口
  async connectRTU(args) { 

    const { port, baudRate, parity, stopBits, dataBits } = args

    // 配置串口参数（根据设备要求调整）
    const serialConfig = {
      port, //"COM4",        // 设备管理器中的 COM 端口
      baudRate: baudRate || 9600,      // 波特率（常见值：9600, 19200, 38400）
      dataBits: dataBits || 8,         // 数据位（通常 8）
      stopBits: stopBits || 1,         // 停止位（通常 1 或 2）
      parity: parity || "none",      // 校验位（"none", "even", "odd"）
      debug: true
    };

    // 连接到设备
    let res = await this.client.connectRTU(serialConfig.port, serialConfig)
    
    // 启用调试模式：监听发送和接收的数据
    // this.client.on("debug", function(data) {
    //   // data 是一个对象，包含以下属性：
    //     // - action: 描述当前动作（如 "send tcp"、"receive tcp"、"send rtu" 等）
    //     // - data: 原始数据（Buffer）
    //     console.log(`Action: ${data.action}`);
    //     console.log(`Data (hex): ${data.data.toString('hex')}`);
    //     console.log("---");
    // });
      
    // 使用内部方法监听接收数据事件
    this.client._port.on('data', (data) => {
        console.log('Received data:', data);
        // 主动向前端发请求
        // const win = Electron.mainWindow.webContents;
        // win.send('ipcMain', { data: data.toString('hex'), channel: 'receive' });
        sendMsg(data.toString('hex'), 'receive');
    });

    return res;
  }  

  async isOpen() { 
    return this.client.isOpen; 
  }

  async debug() {
    let request = ''
    if (this.client._transactions['1']) {
      request = this.client._transactions['1'].request;
      sendMsg(request.toString('hex'), 'send');
    }
  }
  
  // 读线圈数据(01H)
  async readCoils (args) { 
    // 设置从站地址（Slave ID）
    this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
    // 示例：读取线圈寄存器（功能码 0x01）
    let startAddress = args.start || 0;
    let len = args.len || 2;
    let result = await this.client.readCoils(startAddress, len);
    this.debug();
    return result;
  }
  
  // 读离散输入寄存器(02H)
  async readDiscreteInputs (args) {
    this.client.setID(args.id || 1);
    let startAddress = args.start || 0;
    let len = args.len || 2;
    let result = await this.client.readDiscreteInputs(startAddress, len);
    this.debug();
    return result;
  } 
  
  // 读取保持数据(03H)
  async readHolding (args) { 
    // 设置从站地址（Slave ID）
    this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
    // 示例：读取保持寄存器（功能码 0x03）
    let startAddress = args.start || 0;
    let len = args.len || 2;
    let result = this.client.readHoldingRegisters(startAddress, len);
    this.debug();
    return result;
  }

  // 写单个线圈寄存器(05H)
  async writeFC5 (args) { 
    // 设置从站地址（Slave ID）
    this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
    let startAddress = args.start;
    let state = args.state;
    let result = await this.client.writeCoil(startAddress, state);
    return result;
  }

  // 读取输入寄存器(04H)
  async readInput (args) { 
    // 设置从站地址（Slave ID）
    this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
    let startAddress = args.start;
    let len = args.len;
    let result = await this.client.readInputRegisters(startAddress, len);
    return result;
  }

  // 写单个保持寄存器(06H)
  async writeFC6 (args) { 
    // 设置从站地址（Slave ID）
    this.client.setID(args.id || 1); // 替换为你的设备地址（通常 1-247）
    let startAddress = args.start;
    let len = args.len;
    let result = await this.client.writeRegister(startAddress, len);
    return result;    
  }

  async send (args) {
    let bufStr = args.value;
    // 构建PDU：功能码0x01（读线圈），起始地址0x0000，线圈数量0x000A（10个）
    const pdu = Buffer.from(bufStr, 'hex');
    // 使用内部方法发送
    this.client._port.write(pdu);
  }

  async close () {
    // 关闭连接
    this.client.close();
  }


}

ModbusRTUService.toString = () => '[class ModbusRTUService]';
module.exports = ModbusRTUService;